<template>
  <search-form v-if="!searchInCard && searchColumns.length > 0" :columns="searchColumns" :search-param="searchParam" @search="handleFilter" @reset="handleFormReset" />
  <slot name="pageCenter" />
  
  <div v-if="$slots['tableHeader']" class="page-table-header">
    <slot name="tableHeader" />
  </div>
  <el-tabs v-if="tabs.list != null && tabs.list.length > 0" v-model="tabs.value" @tab-click="handleChangeTab">
    <el-tab-pane v-for="(item, index) in tabs.list" :key="index" :name="item.name" :label="item.label" />
  </el-tabs>
  <search-form v-if="searchInCard && searchColumns.length > 0" :columns="searchColumns" :search-param="searchParam" @search="handleFilter" @reset="handleFormReset" />
  <div v-if="$slots['tabsFooter']" class="page-table-header">
    <slot name="tabsFooter" />
  </div>
  <el-table
    ref="pageTableRef"
    border
    v-bind="$attrs"
    v-loading="loading"
    :data="tableData"
    :row-key="dataKey"
    @select="handleSelect"
    @select-all="handleSelectAll"
  >
    <el-table-column
      v-if="showCheckbox"
      type="selection"
      align="center"
      width="55"
      :reserve-selection="reserveSelection"
      :fixed="tableOpFixed"
    />
    <el-table-column
      v-if="showIndex"
      type="index"
      label="序号"
      align="center"
      width="60"
      :fixed="tableOpFixed"
    />
    <template v-for="(column, index) in tableColumns" :key="column.key || column.prop || index">
      <table-column :column="column">
        <template v-for="slot in Object.keys($slots)" #[slot]="scope">
          <slot :name="slot" v-bind="scope" />
        </template>
      </table-column>
    </template>
  </el-table>
  <pagination
    v-model:page="curPageNum"
    v-model:limit="tablePageSize"
    :hidden="!showPagination || total <= 0"
    :total="total"
    :auto-scroll="false"
    @pagination="handlePageChange"
  />
</template>

<script setup>
import { ElMessage, ElMessageBox } from 'element-plus'
import TableColumn from './components/TableColumn.vue'
import SearchForm from '../SearchForm/index.vue'
import { oneOf } from '@/utils/assist'
import Pagination from '../Pagination/index.vue'

const pageTableRef = ref(null)

defineOptions({
  inheritAttrs: false
})

const props = defineProps({
  requestAuto: {
    // 是否默认加载
    type: Boolean,
    default: true
  },
  showPagination: {
    // 是否分页
    type: Boolean,
    default: true
  },
  showCheckbox: {
    // 是否显示复选框
    type: Boolean,
    default: false
  },
  showIndex: {
    // 是否显示序号
    type: Boolean,
    default: true
  },
  dataKey: {
    type: String,
    default: 'id'
  },
  dataLabelKey: {
    type: String,
    default: null
  },
  columns: {
    // 表格数据列字段
    type: Array,
    default: () => []
  },
  searchInitParam: {
    // 附加查询条件
    type: Object,
    default: () => ({})
  },
  searchInCard: {
    // 查询条件是否在 card 中
    type: Boolean,
    default: false
  },
  pageSize: {
    // 表格每页显示条数
    type: Number,
    validator(value) {
      return oneOf(value, [10, 20, 30, 50])
    },
    default: 10
  },
  listApi: {
    // 获取列表数据API接口
    type: Function,
    default: null
  },
  tabs: {
    // 表格tabs标签页，不传时不展示
    type: Object,
    default: () => ({})
  },
  tableOpFixed: {
    // 是否固定表格序号列和操作列
    type: Boolean,
    default: true
  },
  reserveSelection: {
    // 数据更新之后是否保留之前选中的数据
    type: Boolean,
    default: false
  },
  selectedKeys: {
    // 默认选中的表格数据主键字段数组
    type: Array,
    default: () => []
  },
  selectedLabels: {
    // 默认选中的表格数据标签字段数组
    type: Array,
    default: () => []
  },
  selectedData: {
    // 默认选中的表格数据数组
    type: Array,
    default: () => []
  }
})

const emit = defineEmits([
  'request',
  'extra',
  'selection-change',
  'selection-change-data',
  'search',
  'reset'
])

const tablePageSize = ref(props.pageSize)
const curPageNum = ref(1)
const total = ref(0)
const tableData = ref([])
const selectedKeyArr = ref([])
const selectedLabelArr = ref([])
const selectedDataArr = ref([])

const searchColumns = computed(() => {
  return props.columns
    .filter(item => item.search)
    .sort((a, b) => (a.search.order ?? 0) - (b.search.order ?? 0))
})

const tableColumns = computed(() => {
  return props.columns
    .filter(item => !item.hidden)
})

const searchParam = ref({})

const queryParam = ref({})

const updateSearchParam = () => {
  queryParam.value = {}
  Object.assign(queryParam.value, props.searchInitParam, searchParam.value)
}

const loading = ref(true)

const getTableData = async(_curPageNum = curPageNum.value, showLoading = true) => {
  curPageNum.value = _curPageNum
  const params = { ...queryParam.value }
  if (props.showPagination) {
    params.PageNo = curPageNum.value,
    params.PageSize = tablePageSize.value
  }
  let listApi = props.listApi
  if (props.tabs.list?.length > 0) {
    const tab = props.tabs.list.find((item) => item.name === props.tabs.value)
    if (tab?.listApi) {
      listApi = tab.listApi
    }
  }
  showLoading && (loading.value = true)
  await listApi(params).then(async (res) => {
    if (res.data != null) {
      emit('extra', res.data || {})
    }
    await nextTick()
    console.log('getTableData', res)
    const { data = [] } = res
    tableData.value = data
    if (props.selectedKeys.length > 0 && selectedKeyArr.value.length === 0) {
      selectedKeyArr.value = [...props.selectedKeys]
      selectedLabelArr.value = [...props.selectedLabels]
      selectedDataArr.value = [...props.selectedData]
    }
    if (selectedKeyArr.value.length > 0) {
      tableData.value.forEach((row) => {
        if (selectedKeyArr.value.indexOf(row[`${props.dataKey}`]) >= 0) {
          nextTick(() => {
            pageTableRef.value.toggleRowSelection(row, true)
          })
        }
      })
    }
    total.value = res.args?.total || 0
    emit('request', res)
  }).catch(() => {
    tableData.value = []
    total.value = 0
  }).finally(() => {
    loading.value = false
  })
}

const handleChangeTab = async (p) => {
  await nextTick()
  if (props.tabs.key != null) {
    props.searchInitParam[props.tabs.key] = p.props.name
  }
  tableData.value = []
  total.value = 0
  const tab = props.tabs.list.find((item) => item.name === p.props.name)
  if (tab?.listApi) {
    handleFormReset()
  } else {
    handleFilter()
  }
  props.tabs.onChange?.(p.props.name)
}

const handleFilter = async (showLoading) => {
  handleRefresh(1, showLoading)
}

const handleRefresh = async (_curPageNum = curPageNum.value, showLoading = true) => {
  updateSearchParam()
  await getTableData(_curPageNum, showLoading)
  emit('search', queryParam.value)
}

const handleFormReset = () => {
  searchParam.value = {}
  updateSearchParam()
  getTableData(1)
  emit('reset', queryParam.value)
}

const handleReset = () => {
  tableData.value = []
  total.value = 0
  handleFormReset()
}

const handleSelect = (selection, row) => {
  if (selection.length && selection.indexOf(row) !== -1) {
    if (selectedKeyArr.value.indexOf(row[`${props.dataKey}`]) === -1) {
      selectedKeyArr.value.push(row[`${props.dataKey}`])
      selectedLabelArr.value.push(row[`${props.dataLabelKey}`])
      selectedDataArr.value.push(row)
    }
  } else {
    const idIndex = selectedKeyArr.value.indexOf(row[`${props.dataKey}`])
    if (idIndex !== -1) {
      selectedKeyArr.value.splice(idIndex, 1)
      selectedLabelArr.value.splice(idIndex, 1)
      selectedDataArr.value.splice(idIndex, 1)
    }
  }
  emitSelectionChange()
}

const handleSelectAll = (selection) => {
  const selectionIds = selection.map((row) => row[`${props.dataKey}`])
  tableData.value.forEach((row) => {
    const idIndex = selectedKeyArr.value.indexOf(row[`${props.dataKey}`])
    if (selectionIds.indexOf(row[`${props.dataKey}`]) === -1) {
      if (idIndex !== -1) {
        selectedKeyArr.value.splice(idIndex, 1)
        selectedLabelArr.value.splice(idIndex, 1)
        selectedDataArr.value.splice(idIndex, 1)
      }
    } else {
      if (idIndex === -1) {
        selectedKeyArr.value.push(row[`${props.dataKey}`])
        selectedLabelArr.value.push(row[`${props.dataLabelKey}`])
        selectedDataArr.value.push(row)
      }
    }
  })
  emitSelectionChange()
}

const handleClearSelection = () => {
  selectedKeyArr.value = []
  selectedLabelArr.value = []
  selectedDataArr.value = []
  pageTableRef.value.clearSelection()
  emitSelectionChange()
}

const handlePageChange = () => {
  getTableData()
}

const emitSelectionChange = () => {
  const dataObj = {
    keys: selectedKeyArr.value,
  }
  if (props.dataLabelKey != null) {
    dataObj.labels = selectedLabelArr.value
  }
  emit('selection-change', dataObj)
  emit('selection-change-data', selectedDataArr.value)
}

props.searchInitParam[props.tabs.key] = props.tabs.value
if (props.requestAuto) {
  handleFilter()
}

defineExpose({
  loading,
  tableData,
  queryParam,
  selectedKeyArr,
  selectedLabelArr,
  selectedDataArr,
  getTableData,
  handleRefresh,
  handleFilter,
  handleFormReset,
  handleReset,
  handleSelect,
  handleClearSelection,
  handlePageChange
})
</script>